#include "JSON_reader.h"
#include <assert.h>
#include "JSON_parser.h"
#include "weakType/weak_type_allocator.hpp"
#include "weakType/weak_type.h"


typedef wolv::weakType::allocator::Allocator<JSON_parser_struct> parserAllocator;

Json::Reader::Reader( int depth /*= -1*/ )
:depth_(depth), parser_(0)
{
	
}


Json::Reader::~Reader()
{
	_releaseParser();
}

int Json::Reader::parse( const char* p, size_t length, Json::Value& value )
{
	return _parse(p, length, value);
}

int Json::Reader::parse( std::string str, Json::Value& value )
{
	return _parse(str.c_str(), str.length(), value);
}

int Json::Reader::_parse( const char* p, size_t length , Json::Value& value)
{
	_createParser();

	while (!stack_.empty())
	{
		stack_.pop();
	}
	stack_.push(Json::nullType);

	while (!key_.empty())
	{
		key_.pop();
	}

	const char* c = p;
	for (; c != p + length; ++c)
	{
		if (!::JSON_parser_char(parser_, *c))
		{
			::JSON_parser_reset(parser_);
			return -1;
		}
	}

	if (!JSON_parser_done(parser_))
	{
		::JSON_parser_reset(parser_);
		return -1;
	}

	::JSON_parser_reset(parser_);
	value = stack_.top();
	return 0;
}


int Json::Reader::_callback(void* ctx, int type, const JSON_value* value)
{
	Json::Reader* pReader = static_cast<Json::Reader*>(ctx);

	switch(type) 
	{
    case JSON_T_ARRAY_BEGIN: 
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::nullType :
				pReader->stack_.push(Json::arrayType);
				break;
			case Json::objectType :
				pReader->stack_.push(Json::arrayType);
				break;
			case Json::arrayType :
				pReader->stack_.push(Json::arrayType);
				break;
			default:
				return 0;
			}
			break;
		}
	case JSON_T_ARRAY_END:
		{
			Json::Value finish(pReader->stack_.top());
			pReader->stack_.pop();

			switch (pReader->stack_.top().GetType())
			{
			case Json::nullType :
				pReader->stack_.top() = finish;
				break;
			case Json::objectType :
				pReader->stack_.top().append(pReader->key_.top(), finish);
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(finish);
				break;
			default:
				return 0;
			}
			break;
		}

	case JSON_T_OBJECT_BEGIN :
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::nullType :
				pReader->stack_.push(Json::objectType);
				break;
			case Json::objectType :
				pReader->stack_.push(Json::objectType);
				break;
			case Json::arrayType :
				pReader->stack_.push(Json::objectType);
				break;
			default:
				return 0;
			}
			break;

		}

	case JSON_T_OBJECT_END :
		{
			Json::Value finish(pReader->stack_.top());
			pReader->stack_.pop();

			switch (pReader->stack_.top().GetType())
			{
			case Json::nullType :
				pReader->stack_.top() = finish;
				break;
			case Json::objectType :
				pReader->stack_.top().append(pReader->key_.top(), finish);
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(finish);
				break;
			default:
				return 0;
			}
			break;
		}

	case JSON_T_KEY:
		{
			pReader->key_.push(value->vu.str.value);
			break;
		}
	case JSON_T_INTEGER:
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::objectType :
				pReader->stack_.top()[pReader->key_.top()] = (int)value->vu.integer_value;
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append((int)value->vu.integer_value);
				break;
			default:
				return 1;
			}
			break;
		}
	case JSON_T_FLOAT:
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::objectType :
				pReader->stack_.top()[pReader->key_.top()] = value->vu.float_value;
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(value->vu.float_value);
				break;
			default:
				return 1;
			}
			break;
		}
	case JSON_T_NULL:
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::objectType :
				pReader->stack_.top().append(pReader->key_.top(), nullType);
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(nullType);
				break;
			default:
				return 1;
			}
			break;
		}
	case JSON_T_TRUE:
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::objectType :
				pReader->stack_.top().append(pReader->key_.top(), true);
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(true);
				break;
			default:
				return 1;
			}
			break;
		}
	case JSON_T_FALSE:
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::objectType :
				pReader->stack_.top().append(pReader->key_.top(), false);
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(false);
				break;
			default:
				return 1;
			}
			break;
		}

	case JSON_T_STRING:
		{
			switch (pReader->stack_.top().GetType())
			{
			case Json::objectType :
				pReader->stack_.top().append(pReader->key_.top(), value->vu.str.value);
				pReader->key_.pop();
				break;
			case Json::arrayType :
				pReader->stack_.top().append(value->vu.str.value);
				break;
			default:
				return 1;
			}
			break;
		}

	default:
		return 0;
	}

	return 1;
}


int Json::Reader::_createParser()
{
	if (parser_) 
	{
		return 0;	
	}

	JSON_config config;
	::init_JSON_config(&config);

	config.allow_comments = 0;
	config.depth = depth_;
	config.handle_floats_manually = 0;
	config.callback_ctx = this;
	config.callback = Json::Reader::_callback;
	config.malloc = parserAllocator::malloc;
	config.free = parserAllocator::free;

	parser_ = ::new_JSON_parser(&config);
	return 0;
}

int Json::Reader::_releaseParser()
{
	if (parser_)
	{
		::delete_JSON_parser(parser_);
		parser_ = 0;
	}
	
	return 0;
}



